package net.xiaoboli.mgp;

import lombok.SneakyThrows;
import org.apache.commons.lang3.StringUtils;
import org.mybatis.generator.api.*;
import org.mybatis.generator.api.dom.java.*;
import org.mybatis.generator.api.dom.xml.Attribute;
import org.mybatis.generator.api.dom.xml.Document;
import org.mybatis.generator.api.dom.xml.TextElement;
import org.mybatis.generator.api.dom.xml.XmlElement;
import org.mybatis.generator.codegen.mybatis3.MyBatis3FormattingUtilities;
import org.mybatis.generator.config.GeneratedKey;
import org.mybatis.generator.logging.Log;
import org.mybatis.generator.logging.LogFactory;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import static org.mybatis.generator.internal.util.StringUtility.stringHasValue;

public class ServicePlugin extends PluginAdapter {

    // 项目目录，一般为 src/main/java
    private String targetProject;
    private String targetImplProject;

    // service包名，如：service.service
    private String servicePackage;

    // service实现类包名，如：service.service.impl
    private String serviceImplPackage;
    // service接口名前缀
    private String servicePrefix;

    // service接口名后缀
    private String serviceSuffix;

    // mapper接口的父接口
    private String baseMapper;
    // service接口的父接口
    private String baseService;
    // service实现类的父类
    private String baseServiceClass;

    private String recordType;

    private String modelName;

    private FullyQualifiedJavaType model;

    private String serviceName;
    private String serviceImplName;

    private String mapperPublic;
    private String mapperSystem;
    private String mapperNS;
    private String mapperTargetProject;
    private Log log;

    @Override
    public void initialized(IntrospectedTable introspectedTable) {
        this.log = LogFactory.getLog(this.getClass());

        if (!introspectedTable.hasPrimaryKeyColumns()) {
            throw new RuntimeException("Generator table must include primary key");
        }

        //
        targetProject = properties.getProperty("targetProject", "");
        targetImplProject = properties.getProperty("targetImplProject", "");
        servicePackage = properties.getProperty("servicePackage", "system.service");
        serviceImplPackage = properties.getProperty("serviceImplPackage", "");

        //
        String serviceProject = introspectedTable.getTableConfiguration().getProperty("serviceProject");
        if (StringUtils.isNotBlank(serviceProject)) {
            targetProject = serviceProject;
        }

        //
        String serviceImplProject = introspectedTable.getTableConfiguration().getProperty("serviceImplProject");
        if (StringUtils.isNotBlank(serviceImplProject)) {
            targetImplProject = serviceImplProject;
        }

        //
        String sp = introspectedTable.getTableConfiguration().getProperty("servicePackage");
        if (StringUtils.isNotBlank(sp)) {
            servicePackage = sp;
        }

        //
        String tip = introspectedTable.getTableConfiguration().getProperty("serviceImplPackage");
        if (StringUtils.isNotBlank(tip)) {
            serviceImplPackage = tip;
        }

        //
        targetImplProject = stringHasValue(targetImplProject) ? targetImplProject : targetProject;
        serviceImplPackage = stringHasValue(serviceImplPackage) ? serviceImplPackage : (servicePackage + ".impl");

        //

        if (!stringHasValue(targetProject)) {
            throw new RuntimeException("property serviceProject empty");
        }

        if (!stringHasValue(targetImplProject)) {
            throw new RuntimeException("property targetImplProject empty");
        }

        if (!stringHasValue(servicePackage)) {
            throw new RuntimeException("property servicePackage empty");
        }

        if (!stringHasValue(serviceImplPackage)) {
            throw new RuntimeException("property serviceImplPackage empty");
        }

        // --------------------------------------

        servicePrefix = properties.getProperty("servicePrefix");
        servicePrefix = stringHasValue(servicePrefix) ? servicePrefix : "";
        serviceSuffix = properties.getProperty("serviceSuffix", "Service");
        serviceSuffix = stringHasValue(serviceSuffix) ? serviceSuffix : "";
        baseMapper = properties.getProperty("baseMapper", "framework.base.BaseMapper");
        baseService = properties.getProperty("baseService", "framework.base.BaseService");
        baseServiceClass = properties.getProperty("baseServiceClass", "");
        mapperTargetProject = properties.getProperty("mapperTargetProject", "");

    }

    @Override
    public boolean validate(List<String> warnings) {
        boolean valid = true;
        return valid;
    }

    private boolean isOverride(IntrospectedTable introspectedTable, String name) {
        String _override = introspectedTable.getTableConfiguration().getProperty("override");
        if (_override != null) {
            if (_override.equalsIgnoreCase("true")) {
                return true;
            } else if (_override.equalsIgnoreCase("yes")) {
                return true;
            } else if (_override.equalsIgnoreCase("all")) {
                return true;
            } else if (_override.toLowerCase().contains(name)) {
                return true;
            }
        }
        return false;
    }

    private String loadConfig(IntrospectedTable introspectedTable, String name, String defaultValue) {
        String s = introspectedTable.getTableConfiguration().getProperty(name);
        if (StringUtils.isBlank(s)) {
            s = properties.getProperty(name, defaultValue);
        }
        return s;
    }

    private String loadInsertSelective(IntrospectedTable introspectedTable) {
        return loadConfig(introspectedTable, "insertSelective", "no");
    }

    private String loadUpdateBody(IntrospectedTable introspectedTable) {
        return loadConfig(introspectedTable, "updateBody", "yes");
    }

    @SneakyThrows
    @Override
    public List<GeneratedXmlFile> contextGenerateAdditionalXmlFiles(IntrospectedTable introspectedTable) {
        List<GeneratedXmlFile> answer = new ArrayList<>();

        try {

            //mapper
            if (stringHasValue(this.mapperTargetProject)) {
                GeneratedXmlFile mapXml = generateMapperXml(introspectedTable);
                if (PluginUtil.canWrite(mapXml))
                    answer.add(mapXml);
                else
                    log.warn(PluginUtil.canonicalPath(mapXml) + " is exists, skip create, you can delete it and regenerate");
            }

        } catch (Exception exception) {
            exception.printStackTrace();
            throw exception;
        }

        return answer;
    }

    @Override
    public List<GeneratedJavaFile> contextGenerateAdditionalJavaFiles(IntrospectedTable introspectedTable) {

        List<GeneratedJavaFile> answer = new ArrayList<>();

        try {
            this.generateAdditionalJavaFiles(introspectedTable, answer);
        } catch (Exception exception) {
            exception.printStackTrace();
            throw exception;
        }

        return answer;
    }

    /**
     * 添加mapper
     *
     * @param interfaze
     * @param topLevelClass
     * @param introspectedTable
     * @return
     */
    @SneakyThrows
    @Override
    public boolean clientGenerated(Interface interfaze, TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {
        boolean generated = true;

        String recordType = introspectedTable.getBaseRecordType();
        String modelName = recordType.substring(recordType.lastIndexOf(".") + 1);

        //
        //interface SysUserMapper extends Mapper<SysUser>, BaseMapper<SysUser, Long> {
        if (stringHasValue(baseMapper)) {
            interfaze.addImportedType(new FullyQualifiedJavaType(baseMapper));
            interfaze.addImportedType(new FullyQualifiedJavaType(recordType));

            //
            interfaze.addImportedType(introspectedTable.getPrimaryKeyColumns().get(0).getFullyQualifiedJavaType());
            String bs = new FullyQualifiedJavaType(baseMapper).getShortName() + String.format("<%s, %s>", modelName, introspectedTable.getPrimaryKeyColumns().get(0).getFullyQualifiedJavaType().getFullyQualifiedName());
            interfaze.addSuperInterface(new FullyQualifiedJavaType(bs));
        }

        // insertSelective
        if ("yes".equalsIgnoreCase(loadInsertSelective(introspectedTable))) {
            Method m = new Method("insertSelective");
            m.addParameter(new Parameter(new FullyQualifiedJavaType(introspectedTable.getBaseRecordType()), "param"));
            m.setReturnType(new FullyQualifiedJavaType("int"));
            m.addAnnotation("@Override");
            interfaze.addMethod(m);
        }

        // updateBody
        if ("yes".equalsIgnoreCase(loadUpdateBody(introspectedTable))) {
            Method m = new Method("updateBody");
            m.addParameter(new Parameter(new FullyQualifiedJavaType(introspectedTable.getBaseRecordType()), "param"));
            m.setReturnType(new FullyQualifiedJavaType("int"));
            interfaze.addMethod(m);
        }

        // list
        interfaze.addImportedType(new FullyQualifiedJavaType("java.util.List"));
        Method listM = new Method("list");
        listM.addParameter(new Parameter(new FullyQualifiedJavaType(introspectedTable.getBaseRecordType()), "param"));
        listM.setReturnType(new FullyQualifiedJavaType("List<" + introspectedTable.getBaseRecordType() + ">"));
        listM.addAnnotation("@Override");
        interfaze.addMethod(listM);

        // listQuery
        String dtoMethodQuery = (String) introspectedTable.getAttribute("dtoMethodQuery");
        String dtoMethodResult = (String) introspectedTable.getAttribute("dtoMethodResult");
        if (StringUtils.isNotBlank(dtoMethodQuery) && StringUtils.isNotBlank(dtoMethodResult)) {
            interfaze.addImportedType(new FullyQualifiedJavaType(dtoMethodQuery));
            interfaze.addImportedType(new FullyQualifiedJavaType(dtoMethodResult));
            //
            Method listQuery = new Method("listQuery");
            listQuery.addParameter(new Parameter(new FullyQualifiedJavaType(dtoMethodQuery), "param"));
            listQuery.setReturnType(new FullyQualifiedJavaType("List<" + dtoMethodResult + ">"));
            listQuery.addAnnotation("@Override");
            interfaze.addMethod(listQuery);

            interfaze.addImportedType(new FullyQualifiedJavaType("framework.base.ListQueryMapper"));
            interfaze.addSuperInterface(new FullyQualifiedJavaType("ListQueryMapper<"
                    + new FullyQualifiedJavaType(dtoMethodResult).getShortName() + ","
                    + new FullyQualifiedJavaType(dtoMethodQuery).getShortName() + ">"));

        }

        //已有文件检查
        String targetPackage = context.getJavaClientGeneratorConfiguration().getTargetPackage();
        String targetProject = context.getJavaClientGeneratorConfiguration().getTargetProject();
        recordType = introspectedTable.getBaseRecordType();
        String fileName = recordType.substring(recordType.lastIndexOf(".") + 1) + "Mapper.java";

        //已存在检查
        generated = PluginUtil.canWrite(targetProject, targetPackage, fileName);
        if (!generated) {
            if (isOverride(introspectedTable, "mapper")) {
                generated = true;
            }
            //
            log.warn(PluginUtil.canonicalPath(targetProject, targetPackage, fileName) + " is exists, skip create, you can delete it and regenerate");
        }

        //
        return generated;
    }

    @SneakyThrows
    private void generateAdditionalJavaFiles(IntrospectedTable introspectedTable, List<GeneratedJavaFile> answer) {
        recordType = introspectedTable.getBaseRecordType();
        modelName = recordType.substring(recordType.lastIndexOf(".") + 1);
        model = new FullyQualifiedJavaType(recordType);
        serviceName = PluginUtil.serviceName(introspectedTable, servicePackage, servicePrefix, serviceSuffix);
        serviceImplName = PluginUtil.serviceImplName(introspectedTable, serviceImplPackage, servicePrefix, serviceSuffix);

        //
        boolean _over = isOverride(introspectedTable, "service");

        //
        GeneratedJavaFile face = generateServiceInterface(introspectedTable);
        if (PluginUtil.canWrite(face) || _over)
            answer.add(face);
        else
            log.warn(PluginUtil.canonicalPath(face) + " is exists, skip create, you can delete it and regenerate");

        //
        GeneratedJavaFile impl = generateServiceImpl(introspectedTable);
        if (PluginUtil.canWrite(impl) || _over)
            answer.add(impl);
        else
            log.warn(PluginUtil.canonicalPath(impl) + " is exists, skip create, you can delete it and regenerate");
    }

    private GeneratedXmlFile generateMapperXml(IntrospectedTable introspectedTable) {
        String tableName = introspectedTable.getAliasedFullyQualifiedTableNameAtRuntime();

        //
        Document document = new Document(this.mapperPublic, this.mapperSystem);
        XmlElement root = new XmlElement("mapper");
        root.addAttribute(new Attribute("namespace", this.mapperNS));
        document.setRootElement(root);

        //
        document.getRootElement().addElement(new TextElement("<!--\n" +
                "      @mgp-generator\n" +
                "      base/*Mapper由系统生成，不要修改，重新生成将被覆盖\n" +
                "      本同名文件用于撰写自已的SQL，重新生成不会覆盖\n" +
                "      两个文件在运行时将会自动合并\n" +
                "      参考： https://www.xiaobo.li/project/projects/jishi-mgp/wiki\n" +
                "    -->"));

        //
        XmlElement list = new XmlElement("select");
        list.addAttribute(new Attribute("id", "list"));
        list.addAttribute(new Attribute("resultType", introspectedTable.getBaseRecordType()));
        list.addAttribute(new Attribute("parameterType", introspectedTable.getBaseRecordType()));
        list.addElement(new TextElement(String.format(
                "SELECT\n" +
                        "    <include refid=\"All_Column_List\" />\n" +
                        "    FROM %s\n" +
                        "    <where>\n" +
                        "       <include refid=\"whereAll\" />\n" +
                        "    </where>\n" +
                        "    ORDER BY %s DESC",
                tableName,
                MyBatis3FormattingUtilities.getEscapedColumnName(introspectedTable.getPrimaryKeyColumns().get(0))
        )));
        document.getRootElement().addElement(list);

        //
        String dtoMethodQuery = (String) introspectedTable.getAttribute("dtoMethodQuery");
        String dtoMethodResult = (String) introspectedTable.getAttribute("dtoMethodResult");
        if (StringUtils.isNotBlank(dtoMethodQuery) && StringUtils.isNotBlank(dtoMethodResult)) {
            document.getRootElement().addElement(new TextElement("<!-- 联表查询、多表查询修改此方法 -->"));
            //
            list = new XmlElement("select");
            list.addAttribute(new Attribute("id", "listQuery"));
            list.addAttribute(new Attribute("resultType", dtoMethodResult));
            list.addAttribute(new Attribute("parameterType", dtoMethodQuery));
            list.addElement(new TextElement("SELECT"));
            list.addElement(new TextElement("<include refid=\"All_Column_List\" />"));
            list.addElement(new TextElement("FROM " + tableName));
            list.addElement(buildIndexWhere(introspectedTable));
            String keyName = MyBatis3FormattingUtilities.getEscapedColumnName(introspectedTable.getPrimaryKeyColumns().get(0));
            list.addElement(new TextElement("ORDER BY " + keyName + " DESC"));
            //
            document.getRootElement().addElement(list);
        }

        //add
        if ("yes".equalsIgnoreCase(loadInsertSelective(introspectedTable))) {
            document.getRootElement().addElement(new TextElement("<!-- 默认添加方法，仅在需要按特定条件添加时修改 -->"));
            //添加该方法的原因是因为默认的动态生成语句可能因jpa\hibernate等属性设置原因在不同的数据库间出现不同的结果，为统一兼容性，此处使用自定义方法覆盖默认方法
            //同时可以方便使用人员依据情况修改 useGeneratedKeys 等属性
            //在mysql数据库下，此功能开关可以关闭
            XmlElement insert = new XmlElement("insert");
            insert.addAttribute(new Attribute("id", "insertSelective"));
            insert.addAttribute(new Attribute("parameterType", introspectedTable.getBaseRecordType()));
            //
            GeneratedKey generatedKey = introspectedTable.getGeneratedKey();
            if (generatedKey != null) {
                insert.addAttribute(new Attribute("useGeneratedKeys", "true"));
                insert.addAttribute(new Attribute("keyProperty", generatedKey.getColumn()));
            } else {
                List<IntrospectedColumn> primaryKeyColumns = introspectedTable.getPrimaryKeyColumns();
                for (IntrospectedColumn keyColumn : primaryKeyColumns) {
                    if (keyColumn.isAutoIncrement()) {
                        insert.addAttribute(new Attribute("useGeneratedKeys", "true"));
                        insert.addAttribute(new Attribute("keyProperty", keyColumn.getJavaProperty()));
                        break;
                    } else if (keyColumn.isSequenceColumn()) {
                        insert.addAttribute(new Attribute("useGeneratedKeys", "true"));
                        insert.addAttribute(new Attribute("keyProperty", keyColumn.getJavaProperty()));
                        break;
                    }
                }
            }
            //
            insert.addElement(new TextElement("<include refid=\"insertAll\" />"));
            //
//            insert.addElement(new TextElement("INSERT INTO " + tableName + " ("));
//            insert.addElement(new TextElement("<trim suffixOverrides=\",\">"));
//            insert.addElement(new TextElement("    <include refid=\"conditionFields\" />"));
////            addValues(insert, introspectedTable);
//            insert.addElement(new TextElement("</trim>"));
//            insert.addElement(new TextElement(") VALUES ("));
//            insert.addElement(new TextElement("<trim suffixOverrides=\",\">"));
//            insert.addElement(new TextElement("    <include refid=\"conditionValues\" />"));
////            addValues(insert, introspectedTable);
//            insert.addElement(new TextElement("</trim>"));
//            insert.addElement(new TextElement(")"));
            //
            document.getRootElement().addElement(insert);
        }

        //
        if ("yes".equalsIgnoreCase(loadUpdateBody(introspectedTable))) {
            document.getRootElement().addElement(new TextElement("<!-- 主体修改方法：定义指定语句修改信息 -->"));
            //
            list = new XmlElement("update");
            list.addAttribute(new Attribute("id", "updateBody"));
            list.addAttribute(new Attribute("parameterType", introspectedTable.getBaseRecordType()));
            list.addElement(new TextElement("UPDATE " + tableName));
            list.addElement(this.addModifySet(introspectedTable));
            list.addElement(this.addModifyWhere(introspectedTable));
            //
            document.getRootElement().addElement(list);
        }

        //
        String fileName = modelName + properties.getProperty("mapperSuffix", "Mapper.xml");
        String targetPackage = "";
        boolean isMergeable = true;
        GeneratedXmlFile gf = new GeneratedXmlFile(document, fileName, targetPackage, this.mapperTargetProject, isMergeable, context.getXmlFormatter());
        return gf;
    }


    // 生成service接口
    private GeneratedJavaFile generateServiceInterface(IntrospectedTable introspectedTable) {
        FullyQualifiedJavaType service = new FullyQualifiedJavaType(serviceName);

        Interface serviceInterface = new Interface(service);
        serviceInterface.setVisibility(JavaVisibility.PUBLIC);

        // 添加父接口
        if (stringHasValue(baseService)) {
            serviceInterface.addImportedType(new FullyQualifiedJavaType(baseService));
            serviceInterface.addImportedType(new FullyQualifiedJavaType(recordType));
            //
            serviceInterface.addImportedType(introspectedTable.getPrimaryKeyColumns().get(0).getFullyQualifiedJavaType());
            String bs = this.baseService + String.format("<%s, %s>", modelName, introspectedTable.getPrimaryKeyColumns().get(0).getFullyQualifiedJavaType().getFullyQualifiedName());
            serviceInterface.addSuperInterface(new FullyQualifiedJavaType(bs));
        }

        // 包导入
        serviceInterface.addImportedType(model);

        //
        String dtoMethodQuery = (String) introspectedTable.getAttribute("dtoMethodQuery");
        String dtoMethodResult = (String) introspectedTable.getAttribute("dtoMethodResult");
        if (StringUtils.isNotBlank(dtoMethodQuery) && StringUtils.isNotBlank(dtoMethodResult)) {
            serviceInterface.addImportedType(new FullyQualifiedJavaType(dtoMethodQuery));
            serviceInterface.addImportedType(new FullyQualifiedJavaType(dtoMethodResult));
//            serviceInterface.addImportedType(new FullyQualifiedJavaType("com.github.pagehelper.PageInfo"));
//            //
//            Method method = new Method("listQuery");
//            method.addParameter(new Parameter(new FullyQualifiedJavaType(dtoMethodQuery), "query"));
//            method.setReturnType(new FullyQualifiedJavaType("PageInfo<" + dtoMethodResult + ">"));
//            method.addParameter(new Parameter(new FullyQualifiedJavaType("int"), "pageIndex"));
//            method.addParameter(new Parameter(new FullyQualifiedJavaType("int"), "pageSize"));
//            serviceInterface.addMethod(method);
//            //
//            method = new Method("listOne");
//            method.addParameter(new Parameter(new FullyQualifiedJavaType(dtoMethodQuery), "query"));
//            method.setReturnType(new FullyQualifiedJavaType(dtoMethodResult));
//            serviceInterface.addMethod(method);

            serviceInterface.addImportedType(new FullyQualifiedJavaType("framework.base.ListQueryService"));
            serviceInterface.addSuperInterface(new FullyQualifiedJavaType("ListQueryService<"
                    + new FullyQualifiedJavaType(dtoMethodResult).getShortName() + ", "
                    + new FullyQualifiedJavaType(dtoMethodQuery).getShortName() + ">"));
        }

        // batch
        String batch = introspectedTable.getTableConfiguration().getProperty("batch");
        if (StringUtils.isNotBlank(batch) && "no".equals(batch)) {
            //
        } else {
            serviceInterface.addImportedType(new FullyQualifiedJavaType(introspectedTable.getMyBatis3JavaMapperType()));
            serviceInterface.addImportedType(new FullyQualifiedJavaType("framework.base.BatchService"));
            serviceInterface.addSuperInterface(new FullyQualifiedJavaType("BatchService<"
                    + new FullyQualifiedJavaType(recordType).getShortName()
                    + ","
                    + new FullyQualifiedJavaType(introspectedTable.getMyBatis3JavaMapperType()).getShortName()
                    + ">"));
            //
            Method method = new Method("getMapperClass");
            method.setReturnType(new FullyQualifiedJavaType("Class<" + new FullyQualifiedJavaType(introspectedTable.getMyBatis3JavaMapperType()).getShortName() + ">"));
            method.setDefault(true);
            method.addBodyLine("return " + new FullyQualifiedJavaType(introspectedTable.getMyBatis3JavaMapperType()).getShortName() + ".class;");
            serviceInterface.addMethod(method);
        }

        // updateBody
        if ("yes".equalsIgnoreCase(loadUpdateBody(introspectedTable))) {
            serviceInterface.addImportedType(new FullyQualifiedJavaType(introspectedTable.getBaseRecordType()));
            //
            Method method = new Method("updateBody");
            method.setReturnType(new FullyQualifiedJavaType("int"));
            method.addParameter(new Parameter(new FullyQualifiedJavaType(introspectedTable.getBaseRecordType()), "param"));
            serviceInterface.addMethod(method);
        }

        //
        GeneratedJavaFile gjf = new GeneratedJavaFile(serviceInterface, targetProject, context.getJavaFormatter());

        //
        return gjf;
    }

    // 生成serviceImpl实现类
    private GeneratedJavaFile generateServiceImpl(IntrospectedTable introspectedTable) {
        FullyQualifiedJavaType service = new FullyQualifiedJavaType(serviceName);
        FullyQualifiedJavaType serviceImpl = new FullyQualifiedJavaType(serviceImplName);
        TopLevelClass clazz = new TopLevelClass(serviceImpl);
        //描述类的作用域修饰符
        clazz.setVisibility(JavaVisibility.PUBLIC);
        //描述类 引入的类
        clazz.addImportedType(service);

        // 包导入
//        clazz.addImportedType(model);
//        clazz.addImportedType(new FullyQualifiedJavaType("java.util.List"));

        //描述类 的实现接口类
        clazz.addSuperInterface(service);
        if (stringHasValue(baseServiceClass)) {
            clazz.addImportedType(baseServiceClass);
            clazz.addImportedType(recordType);

            //
            clazz.addImportedType(introspectedTable.getPrimaryKeyColumns().get(0).getFullyQualifiedJavaType());
            String bs = this.baseServiceClass + String.format("<%s, %s>", modelName, introspectedTable.getPrimaryKeyColumns().get(0).getFullyQualifiedJavaType().getFullyQualifiedName());
            clazz.setSuperClass(new FullyQualifiedJavaType(bs));
        }
        clazz.addImportedType(new FullyQualifiedJavaType("org.springframework.stereotype.Service"));
        clazz.addAnnotation("@Service");

        //
        String daoFieldType = introspectedTable.getMyBatis3JavaMapperType();
        String daoFieldName = "mapper";
        //描述类的成员属性
        Field daoField = new Field(daoFieldName, new FullyQualifiedJavaType(daoFieldType));
        clazz.addImportedType(new FullyQualifiedJavaType(daoFieldType));
        clazz.addImportedType(new FullyQualifiedJavaType("org.springframework.beans.factory.annotation.Autowired"));
        clazz.addImportedType(new FullyQualifiedJavaType("lombok.Getter"));
        //描述成员属性 的注解
        daoField.addAnnotation("@Autowired");
        daoField.addAnnotation("@Getter");
        //描述成员属性修饰符
        daoField.setVisibility(JavaVisibility.PRIVATE);
        clazz.addField(daoField);

        //
        String dtoMethodQuery = (String) introspectedTable.getAttribute("dtoMethodQuery");
        String dtoMethodResult = (String) introspectedTable.getAttribute("dtoMethodResult");
        if (StringUtils.isNotBlank(dtoMethodQuery) && StringUtils.isNotBlank(dtoMethodResult)) {
//            clazz.addImportedType(new FullyQualifiedJavaType(dtoMethodQuery));
//            clazz.addImportedType(new FullyQualifiedJavaType(dtoMethodResult));
//            clazz.addImportedType(new FullyQualifiedJavaType("com.github.pagehelper.PageHelper"));
//            clazz.addImportedType(new FullyQualifiedJavaType("com.github.pagehelper.PageInfo"));
//            //
//            Method method = new Method("listQuery");
//            method.setVisibility(JavaVisibility.PUBLIC);
//            method.addParameter(new Parameter(new FullyQualifiedJavaType(dtoMethodQuery), "query"));
//            method.setReturnType(new FullyQualifiedJavaType("PageInfo<" + dtoMethodResult + ">"));
//            method.addParameter(new Parameter(new FullyQualifiedJavaType("int"), "pageIndex"));
//            method.addParameter(new Parameter(new FullyQualifiedJavaType("int"), "pageSize"));
//            method.addBodyLine("PageHelper.startPage(pageIndex, pageSize);");
//            method.addBodyLine("List<" + new FullyQualifiedJavaType(dtoMethodResult).getShortName() + "> list = mapper.listQuery(query);");
//            method.addBodyLine("return PageInfo.of(list);");
//            clazz.addMethod(method);
//            //
//            method = new Method("listOne");
//            method.setVisibility(JavaVisibility.PUBLIC);
//            method.addParameter(new Parameter(new FullyQualifiedJavaType(dtoMethodQuery), "query"));
//            method.setReturnType(new FullyQualifiedJavaType(dtoMethodResult));
//            method.addBodyLine("PageHelper.startPage(1, 1, false);");
//            method.addBodyLine("List<" + new FullyQualifiedJavaType(dtoMethodResult).getShortName() + "> list = mapper.listQuery(query);");
//            method.addBodyLine("return list.size() == 0 ? null : list.get(0);");
//            clazz.addMethod(method);
        }

//        //
//        String overrideDelete = properties.getProperty("overrideDelete", "true");
//        if ("true".equals(overrideDelete)) {
//            if (introspectedTable.getPrimaryKeyColumns().size() > 0) {
//                String field = introspectedTable.getPrimaryKeyColumns().get(0).getJavaProperty();
//                String id = String.valueOf(field.charAt(0)).toUpperCase() + field.substring(1);
//                //
//                Method method = new Method("delete");
//                method.setVisibility(JavaVisibility.PUBLIC);
//                method.addAnnotation("@Override");
//                method.addParameter(new Parameter(model, "param"));
//                method.setReturnType(new FullyQualifiedJavaType("java.lang.Integer"));
//                method.addBodyLine("int rows = 0;");
//                method.addBodyLine("for (" + modelName + " item : this.load(param)) {");
//                method.addBodyLine("rows += this.deleteById(item.get" + id + "());");
//                method.addBodyLine("}");
//                method.addBodyLine("return rows;");
//                clazz.addMethod(method);
//            }
//        }

        // updateBody
        if ("yes".equalsIgnoreCase(loadUpdateBody(introspectedTable))) {
            clazz.addImportedType(new FullyQualifiedJavaType(introspectedTable.getBaseRecordType()));
            //
            Method method = new Method("updateBody");
            method.setReturnType(new FullyQualifiedJavaType("int"));
            method.addParameter(new Parameter(new FullyQualifiedJavaType(introspectedTable.getBaseRecordType()), "param"));
            method.addBodyLine("return mapper.updateBody(param);");
            method.addAnnotation("@Override");
            method.setVisibility(JavaVisibility.PUBLIC);
            clazz.addMethod(method);
        }

        //
        GeneratedJavaFile gjf2 = new GeneratedJavaFile(clazz, targetImplProject, context.getJavaFormatter());
        return gjf2;
    }

    /**
     * 添加自定义方法到mapper
     */
    @Override
    public boolean sqlMapDocumentGenerated(Document document, IntrospectedTable introspectedTable) {
        String tableName = introspectedTable.getAliasedFullyQualifiedTableNameAtRuntime();

        //All_Column_List
        this.addAllColumnElement(document.getRootElement(), introspectedTable);

        //All where
        this.addAllWhere(document.getRootElement(), introspectedTable);

        //All set
        this.addAllSet(document.getRootElement(), introspectedTable);

        //add
        this.addAddElement(document.getRootElement(), introspectedTable);

        //key name
        String keyActualName = "id";
        String keyClauseName = "#{id}";
        IntrospectedColumn primaryKeyColumn = null;
        for (IntrospectedColumn item : introspectedTable.getPrimaryKeyColumns()) {
            primaryKeyColumn = item;
            keyActualName = item.getActualColumnName();
            // keyCamelName = MyBatis3FormattingUtilities.getEscapedColumnName(item);
            // keyClauseName = MyBatis3FormattingUtilities.getParameterClause(item);
            keyClauseName = "#{id,jdbcType=" + item.getJdbcTypeName() + "}";
            break;
        }

        //add
//        if ("base".equalsIgnoreCase(loadInsertSelective(introspectedTable))) {
////            document.getRootElement().addElement(new TextElement("<!-- insertSelective 添加方法 -->"));
//            document.getRootElement().addElement(new TextElement("<!-- insertSelective 方法 SQL, 修正动态生成时的主键异常问题 -->"));
//            document.getRootElement().addElement(new TextElement("<!-- Use SQL to implement insertSelective method to fix primary key exception issue during dynamic build -->"));
//            //add
//            XmlElement insert = new XmlElement("insert");
//            insert.addAttribute(new Attribute("id", "insertSelective"));
//            insert.addAttribute(new Attribute("parameterType", introspectedTable.getBaseRecordType()));
//            //
//            GeneratedKey generatedKey = introspectedTable.getGeneratedKey();
//            if (generatedKey != null) {
//                insert.addAttribute(new Attribute("useGeneratedKeys", "true"));
//                insert.addAttribute(new Attribute("keyProperty", generatedKey.getColumn()));
//            }
//            //
//            insert.addElement(new TextElement("INSERT INTO " + tableName + " ("));
//            insert.addElement(new TextElement("<trim suffixOverrides=\",\">"));
//            insert.addElement(new TextElement("    <include refid=\"conditionFields\" />"));
//            insert.addElement(new TextElement("</trim>"));
//            insert.addElement(new TextElement(") VALUES ("));
//            insert.addElement(new TextElement("<trim suffixOverrides=\",\">"));
//            insert.addElement(new TextElement("    <include refid=\"conditionValues\" />"));
//            insert.addElement(new TextElement("</trim>"));
//            insert.addElement(new TextElement(")"));
//            //
//            document.getRootElement().addElement(insert);
//        }

        //loadByIds
        XmlElement loadByIds = new XmlElement("select");
        loadByIds.addAttribute(new Attribute("id", "loadByIds"));
        //loadByIds.addAttribute(new Attribute("resultMap", "BaseResultMap"));
        loadByIds.addAttribute(new Attribute("resultType", introspectedTable.getBaseRecordType()));
        loadByIds.addElement(new TextElement(String.format(
                "SELECT\n" +
                        "    <include refid=\"All_Column_List\" />\n" +
                        "    FROM %s\n" +
                        "    <where>\n" +
                        "        <choose>\n" +
                        "            <when test=\"ids != null and ids.size() != 0\">\n" +
                        "                %s IN \n" +
                        "                <foreach collection=\"ids\" item=\"id\" index=\"index\" open=\"(\" close=\")\" separator=\",\">#{id}</foreach>\n" +
                        "            </when>\n" +
                        "            <otherwise>\n" +
                        "                1 = 0\n" +
                        "            </otherwise>\n" +
                        "        </choose>\n" +
                        "    </where>",
                tableName,
                keyActualName
        )));
        document.getRootElement().addElement(loadByIds);

        //loadByNotIds
        XmlElement loadByNotIds = new XmlElement("select");
        loadByNotIds.addAttribute(new Attribute("id", "loadByNotIds"));
        // loadByNotIds.addAttribute(new Attribute("resultMap", "BaseResultMap"));
        loadByNotIds.addAttribute(new Attribute("resultType", introspectedTable.getBaseRecordType()));
        loadByNotIds.addElement(new TextElement(String.format(
                "SELECT\n" +
                        "    <include refid=\"All_Column_List\" />\n" +
                        "    FROM %s\n" +
                        "    <where>\n" +
                        "        <choose>\n" +
                        "            <when test=\"ids != null and ids.size() != 0\">\n" +
                        "                %s NOT IN \n" +
                        "                <foreach collection=\"ids\" item=\"id\" index=\"index\" open=\"(\" close=\")\" separator=\",\">#{id}</foreach>\n" +
                        "            </when>\n" +
                        "            <otherwise>\n" +
                        "                1 = 0\n" +
                        "            </otherwise>\n" +
                        "        </choose>\n" +
                        "    </where>",
                tableName,
                introspectedTable.getPrimaryKeyColumns().get(0).getActualColumnName()
        )));
        document.getRootElement().addElement(loadByNotIds);

        //deleteByIds
        XmlElement deleteByIds = new XmlElement("delete");
        deleteByIds.addAttribute(new Attribute("id", "deleteByIds"));
        deleteByIds.addElement(new TextElement(String.format(
                "DELETE FROM %s \n" +
                        "    <where>\n" +
                        "        <choose>\n" +
                        "            <when test=\"ids != null and ids.size() != 0\">\n" +
                        "                %s IN \n" +
                        "                <foreach collection=\"ids\" item=\"id\" index=\"index\" open=\"(\" close=\")\" separator=\",\">#{id}</foreach>\n" +
                        "            </when>\n" +
                        "            <otherwise>\n" +
                        "                1 = 0\n" +
                        "            </otherwise>\n" +
                        "        </choose>\n" +
                        "    </where>",
                tableName,
                introspectedTable.getPrimaryKeyColumns().get(0).getActualColumnName()
        )));
        document.getRootElement().addElement(deleteByIds);

        //deleteByNotIds
        XmlElement deleteByNotIds = new XmlElement("delete");
        deleteByNotIds.addAttribute(new Attribute("id", "deleteByNotIds"));
        deleteByNotIds.addElement(new TextElement(String.format(
                "DELETE FROM %s \n" +
                        "    <where>\n" +
                        "        <choose>\n" +
                        "            <when test=\"ids != null and ids.size() != 0\">\n" +
                        "                %s NOT IN \n" +
                        "                <foreach collection=\"ids\" item=\"id\" index=\"index\" open=\"(\" close=\")\" separator=\",\">#{id}</foreach>\n" +
                        "            </when>\n" +
                        "            <otherwise>\n" +
                        "                1 = 0\n" +
                        "            </otherwise>\n" +
                        "        </choose>\n" +
                        "    </where>",
                tableName,
                introspectedTable.getPrimaryKeyColumns().get(0).getActualColumnName()
        )));
        document.getRootElement().addElement(deleteByNotIds);

//        //loadById2
//        XmlElement loadById2 = new XmlElement("select");
//        loadById2.addAttribute(new Attribute("id", "loadById2"));
//        loadById2.addAttribute(new Attribute("resultType", introspectedTable.getBaseRecordType()));
//        loadById2.addElement(new TextElement(String.format(
//                "SELECT\n" +
//                        "    <include refid=\"All_Column_List\" />\n" +
//                        "    FROM %s WHERE %s=%s",
//                tableName, keyActualName, keyClauseName
//        )));
//        document.getRootElement().addElement(loadById2);

//        //updateById2
//        XmlElement updateById2 = new XmlElement("update");
//        updateById2.addAttribute(new Attribute("id", "updateById2"));
//        updateById2.addElement(new TextElement(String.format(
//                "UPDATE %s\n" +
//                        "    <set>\n" +
//                        "        <include refid=\"setAll\" />\n" +
//                        "    </set>\n" +
//                        "    WHERE %s=%s",
//                tableName, keyActualName, keyClauseName
//        )));
//        document.getRootElement().addElement(updateById2);

//        //deleteById2
//        XmlElement deleteById2 = new XmlElement("delete");
//        deleteById2.addAttribute(new Attribute("id", "deleteById2"));
//        deleteById2.addElement(new TextElement(String.format(
//                "DELETE FROM %s WHERE %s=%s",
//                tableName, keyActualName, keyClauseName
//        )));
//        document.getRootElement().addElement(deleteById2);

        //暂存，以便后扩展XML生成
        this.mapperPublic = document.getPublicId();
        this.mapperSystem = document.getSystemId();
        for (Attribute attribute : document.getRootElement().getAttributes()) {
            if (attribute.getName().equals("namespace")) {
                this.mapperNS = attribute.getValue();
                break;
            }
        }

        //
        return super.sqlMapDocumentGenerated(document, introspectedTable);
    }

    private void addFields(XmlElement element, IntrospectedTable introspectedTable) {
        //循环拼接条件列
        for (IntrospectedColumn introspectedColumn : introspectedTable.getAllColumns()) {
            element.addElement(new TextElement(
                            new StringBuffer()
                                    .append("\t")
                                    .append("<if test=\"" + introspectedColumn.getJavaProperty() + " != null" + "\">")
                                    .append(MyBatis3FormattingUtilities.getEscapedColumnName(introspectedColumn))
                                    .append(",</if>")
                                    .toString()
                    )
            );
        }
    }

    private void addValues(XmlElement element, IntrospectedTable introspectedTable) {
        //循环拼接条件列
        for (IntrospectedColumn introspectedColumn : introspectedTable.getAllColumns()) {
            element.addElement(new TextElement(
                            new StringBuffer()
                                    .append("\t")
                                    .append("<if test=\"" + introspectedColumn.getJavaProperty() + " != null" + "\">")
                                    .append(MyBatis3FormattingUtilities.getParameterClause(introspectedColumn))
                                    .append(",</if>")
                                    .toString()
                    )
            );
        }
    }

    private void addAddElement(XmlElement element, IntrospectedTable introspectedTable) {
//        List<String> autoList = new ArrayList<>();
        //
        XmlElement fields = new XmlElement("sql");
        fields.addAttribute(new Attribute("id", "conditionFields"));
        //循环拼接条件列
        for (IntrospectedColumn introspectedColumn : introspectedTable.getAllColumns()) {
//            if (introspectedColumn.isGeneratedColumn()) {
//                autoList.add(introspectedColumn.getActualColumnName());
//            }

            // 拼接 if
            XmlElement ele = new XmlElement("if");
            StringBuilder sb = new StringBuilder();

            // java对象字段
            sb.append(introspectedColumn.getJavaProperty());
            sb.append(" != null ");
            ele.addAttribute(new Attribute("test", sb.toString()));


            sb.setLength(0);
            sb.append(MyBatis3FormattingUtilities
                    .getEscapedColumnName(introspectedColumn));
//            sb.append(" = ");
//            sb.append(MyBatis3FormattingUtilities
//                    .getParameterClause(introspectedColumn));
            sb.append(",");


            ele.addElement(new TextElement(sb.toString()));
            fields.addElement(ele);
        }
        //
        element.addElement(fields);

        // ----
        XmlElement values = new XmlElement("sql");
        values.addAttribute(new Attribute("id", "conditionValues"));
        //循环拼接条件列
        for (IntrospectedColumn introspectedColumn : introspectedTable.getAllColumns()) {

            // 拼接 if
            XmlElement ele = new XmlElement("if");
            StringBuilder sb = new StringBuilder();

            // 对象字段
            sb.append(introspectedColumn.getJavaProperty());
            sb.append(" != null ");
            ele.addAttribute(new Attribute("test", sb.toString()));


            sb.setLength(0);
//            sb.append(MyBatis3FormattingUtilities
//                    .getEscapedColumnName(introspectedColumn));
//            sb.append(" = ");
            sb.append(MyBatis3FormattingUtilities
                    .getParameterClause(introspectedColumn));
            sb.append(",");


            ele.addElement(new TextElement(sb.toString()));
            values.addElement(ele);
        }
        //
        element.addElement(values);

        //
        XmlElement insert = new XmlElement("sql");
        insert.addAttribute(new Attribute("id", "insertAll"));
        insert.addElement(new TextElement("INSERT INTO " + introspectedTable.getAliasedFullyQualifiedTableNameAtRuntime() + " ("));
        insert.addElement(new TextElement("<trim suffixOverrides=\",\">"));
        insert.addElement(new TextElement("    <include refid=\"conditionFields\" />"));
        insert.addElement(new TextElement("</trim>"));
        insert.addElement(new TextElement(") VALUES ("));
        insert.addElement(new TextElement("<trim suffixOverrides=\",\">"));
        insert.addElement(new TextElement("    <include refid=\"conditionValues\" />"));
        insert.addElement(new TextElement("</trim>"));
        insert.addElement(new TextElement(")"));
        //
        element.addElement(insert);

    }

//    private boolean isInsertSelectiveSql(IntrospectedTable introspectedTable) {
//        return switchConfig(introspectedTable, "insertSelectiveSql");
//    }

//    private boolean isSqlUpdate(IntrospectedTable introspectedTable) {
//        return switchConfig(introspectedTable, "sqlUpdate");
//    }

//    private boolean switchConfig(IntrospectedTable introspectedTable, String name) {
//        boolean insertSelective = true;
//        String _is = introspectedTable.getTableConfiguration().getProperty(name);
//        if ("no".equalsIgnoreCase(_is)) {
//            insertSelective = false;
//        } else if ("yes".equalsIgnoreCase(_is)) {
//            insertSelective = true;
//        } else {
//            _is = properties.getProperty(name, "");
//            if ("no".equalsIgnoreCase(_is)) {
//                insertSelective = false;
//            }
//        }
//        return insertSelective;
//    }

    private void addAllColumnElement(XmlElement element, IntrospectedTable introspectedTable) {
        XmlElement list = new XmlElement("sql");
        list.addAttribute(new Attribute("id", "All_Column_List"));

        // blob
//        list.addElement(new TextElement("<include refid=\"" + introspectedTable.getBaseColumnListId() + "\" />"));
//        if (introspectedTable.hasBLOBColumns()) {
//            list.addElement(new TextElement(","));
//            list.addElement(new TextElement("<include refid=\"" + introspectedTable.getBlobColumnListId() + "\" />"));
//        }

        int indent = 4;
        List<IntrospectedColumn> allColumns = introspectedTable.getAllColumns();
        StringBuffer buffer = new StringBuffer();
        for (int i = 0; i < allColumns.size(); i++) {
            IntrospectedColumn column = allColumns.get(i);
            //
//            if ((i + 1) % 10 == 0) {
//                list.addElement(new TextElement(buffer.toString()));
//                buffer = new StringBuffer();
//            }
            //
            if ((buffer.length() + column.getActualColumnName().length() + 2 + indent) >= 100) {
                list.addElement(new TextElement(buffer.toString()));
                buffer = new StringBuffer();
            }
            buffer.append(column.getActualColumnName()).append(", ");
        }
        if (buffer.length() > 0) {
            list.addElement(new TextElement(buffer.toString().substring(0, buffer.length() - 2)));
        }
        element.addElement(list);
    }

    private void addAllSet(XmlElement element, IntrospectedTable introspectedTable) {
        //
        XmlElement sql = new XmlElement("sql");
        sql.addAttribute(new Attribute("id", "setAll"));

        //循环拼接条件列
        for (IntrospectedColumn introspectedColumn : introspectedTable.getAllColumns()) {

            //跳过主键
            boolean isPK = false;
            for (IntrospectedColumn primaryKeyColumn : introspectedTable.getPrimaryKeyColumns()) {
                if (primaryKeyColumn.getActualColumnName().equals(introspectedColumn.getActualColumnName())) {
                    isPK = true;
                    break;
                }
            }

            if (isPK) {
                //跳过主键
                continue;
            }

            if (introspectedColumn.isAutoIncrement()) {
                //跳过自增
                continue;
            }

            // 拼接 if
            XmlElement notNullElement = new XmlElement("if");
            StringBuilder sb = new StringBuilder();

            // java对象字段
            sb.append(introspectedColumn.getJavaProperty());
            sb.append(" != null ");
            notNullElement.addAttribute(new Attribute("test", sb.toString()));
            sb.setLength(0);

            sb.append(MyBatis3FormattingUtilities
                    .getEscapedColumnName(introspectedColumn));
            sb.append(" = ");
            sb.append(MyBatis3FormattingUtilities
                    .getParameterClause(introspectedColumn));

            sb.append(",");
            notNullElement.addElement(new TextElement(sb.toString()));

            sql.addElement(notNullElement);
        }

        //
        element.addElement(sql);
    }

    private void addAllWhere(XmlElement element, IntrospectedTable introspectedTable) {
        //
        XmlElement list = new XmlElement("sql");
        list.addAttribute(new Attribute("id", "whereAll"));

        //循环拼接条件列
        for (IntrospectedColumn introspectedColumn : introspectedTable.getAllColumns()) {
            // 拼接 if
            XmlElement notNullElement = new XmlElement("if");
            StringBuilder sb = new StringBuilder();

            // java对象字段
            sb.append(introspectedColumn.getJavaProperty());
            sb.append(" != null ");

            // 字符型 增加 and column != ''
            // introspectedColumn.isJdbcCharacterColumn()
            if (introspectedColumn.isStringColumn()) {
                sb.append("and ");

                // java对象字段
                sb.append(introspectedColumn.getJavaProperty());
                sb.append(" != '' ");
            }
            notNullElement.addAttribute(new Attribute("test", sb.toString()));
            sb.setLength(0);

            sb.append(" AND ");
            sb.append(MyBatis3FormattingUtilities
                    .getEscapedColumnName(introspectedColumn));
            sb.append(" = ");
            sb.append(MyBatis3FormattingUtilities
                    .getParameterClause(introspectedColumn));
            notNullElement.addElement(new TextElement(sb.toString()));
            list.addElement(notNullElement);
        }

        element.addElement(list);
    }

    @SneakyThrows
    private XmlElement buildIndexWhere(IntrospectedTable introspectedTable) {
        XmlElement element = new XmlElement("where");

        //
        Set<String> nameSet = PluginUtil.getIndexColumns(introspectedTable);

        if (nameSet.size() == 0) {
            element.addElement(new TextElement("<!-- NO INDEX -->"));
            element.addElement(new TextElement("1 = 0"));
            return element;
        }

        // JavaBeansUtil.getCamelCaseString(column.getIndexType(), false)

        //
//        keySet.addAll(introspectedTable.getPrimaryKeyColumns());
//        keySet.addAll(introspectedTable.getIndex);
        List<IntrospectedColumn> keySet = new ArrayList<>();
        for (IntrospectedColumn introspectedColumn : introspectedTable.getAllColumns()) {
            if (nameSet.contains(introspectedColumn.getActualColumnName())) {
                keySet.add(introspectedColumn);
            }
        }

        //循环拼接条件列
        for (IntrospectedColumn introspectedColumn : keySet) {
            // 拼接 if
            XmlElement notNullElement = new XmlElement("if");
            StringBuilder sb = new StringBuilder();

            // java对象字段
            sb.append(introspectedColumn.getJavaProperty());
            sb.append(" != null ");

            // 字符型 增加 and column != ''
            // introspectedColumn.isJdbcCharacterColumn()
            if (introspectedColumn.isStringColumn()) {
                sb.append("and ");

                // java对象字段
                sb.append(introspectedColumn.getJavaProperty());
                sb.append(" != '' ");
            }
            notNullElement.addAttribute(new Attribute("test", sb.toString()));
            sb.setLength(0);

            sb.append(" AND ");
            sb.append(MyBatis3FormattingUtilities
                    .getEscapedColumnName(introspectedColumn));
            sb.append(" = ");
            sb.append(MyBatis3FormattingUtilities
                    .getParameterClause(introspectedColumn));
            notNullElement.addElement(new TextElement(sb.toString()));
            //
            element.addElement(notNullElement);
        }

        //
        return element;
    }


    private XmlElement addModifyWhere(IntrospectedTable introspectedTable) {
        XmlElement element = new XmlElement("where");
        //循环拼接条件列
        for (IntrospectedColumn column : introspectedTable.getPrimaryKeyColumns()) {
            element.addElement(
                    new TextElement(
                            new StringBuffer()
                                    .append(" AND ")
                                    .append(MyBatis3FormattingUtilities.getEscapedColumnName(column))
                                    .append(" = ")
                                    .append(MyBatis3FormattingUtilities.getParameterClause(column))
                                    .toString()
                    )
            );
        }
        //
        return element;
    }

    private XmlElement addModifySet(IntrospectedTable introspectedTable) {
        XmlElement element = new XmlElement("set");
        //主键
        HashSet<String> keyFields = new HashSet<>();
        for (IntrospectedColumn primaryKeyColumn : introspectedTable.getPrimaryKeyColumns()) {
            keyFields.add(primaryKeyColumn.getActualColumnName());
        }
        //IGNORE
        HashSet<String> ignoreFields = new HashSet<>();
        for (String item : properties.getProperty("ignoreUpdateFields", "").split(",")) {
            ignoreFields.add(item);
        }
        //设置
        for (IntrospectedColumn column : introspectedTable.getAllColumns()) {
            if (ignoreFields.contains(column.getActualColumnName())
                    || keyFields.contains(column.getActualColumnName())
                    || column.isAutoIncrement()) {
                element.addElement(
                        new TextElement(
                                new StringBuffer().append("<!-- ")
                                        .append(MyBatis3FormattingUtilities.getEscapedColumnName(column))
                                        .append(" = ")
                                        .append(MyBatis3FormattingUtilities.getParameterClause(column))
                                        .append(",")
                                        .append(" -->")
                                        .toString()
                        )
                );
            } else {
                element.addElement(
                        new TextElement(
                                new StringBuffer()
                                        .append(MyBatis3FormattingUtilities.getEscapedColumnName(column))
                                        .append(" = ")
                                        .append(MyBatis3FormattingUtilities.getParameterClause(column))
                                        .append(",")
                                        .toString()
                        )
                );
            }
        }
        //
        return element;
    }

//    private void addListElement(XmlElement element, IntrospectedTable introspectedTable) {
//        //
//        XmlElement list = new XmlElement("select");
//
//        list.addAttribute(new Attribute("id", "list"));
//        list.addAttribute(new Attribute("resultMap", introspectedTable.getBaseResultMapId()));
//        list.addAttribute(new Attribute("parameterType", introspectedTable.getBaseRecordType()));
//        list.addElement(new TextElement("SELECT"));
//        list.addElement(new TextElement("<include refid=\"Base_Column_List\" />"));
//
//        // 是否有blob字段
////        if (introspectedTable.hasBLOBColumns()) {
////            answer.addElement(new TextElement(",")); //$NON-NLS-1$
////            answer.addElement(getBlobColumnListElement());
////        }
//
//        list.addElement(new TextElement("FROM " + introspectedTable.getAliasedFullyQualifiedTableNameAtRuntime()));
//        XmlElement whereXmlElement = new XmlElement("where");
//        list.addElement(whereXmlElement);
//
//        whereXmlElement.addElement(new TextElement(" 1=1 "));
//
//        //循环拼接条件列
//        for (IntrospectedColumn introspectedColumn : introspectedTable.getAllColumns()) {
//            // 拼接 if
//            XmlElement selectNotNullElement = new XmlElement("if");
//            StringBuilder sb = new StringBuilder();
//
//            // java对象字段
//            sb.append(introspectedColumn.getJavaProperty());
//            sb.append(" != null ");
//
//            // 字符型 增加 and column != ''
//            if (introspectedColumn.isJdbcCharacterColumn()) {
//                sb.append("and ");
//
//                // java对象字段
//                sb.append(introspectedColumn.getJavaProperty());
//                sb.append(" != '' ");
//            }
//            selectNotNullElement.addAttribute(new Attribute("test", sb.toString()));
//            sb.setLength(0);
//
//            sb.append(" AND ");
//            sb.append(MyBatis3FormattingUtilities
//                    .getEscapedColumnName(introspectedColumn));
//            sb.append(" = ");
//            sb.append(MyBatis3FormattingUtilities
//                    .getParameterClause(introspectedColumn));
//            selectNotNullElement.addElement(new TextElement(sb.toString()));
//            whereXmlElement.addElement(selectNotNullElement);
//        }
//
//        element.addElement(list);
//    }

    @Override
    public boolean clientCountByExampleMethodGenerated(Method method, Interface interfaze, IntrospectedTable introspectedTable) {
        return false;
    }

    @Override
    public boolean clientCountByExampleMethodGenerated(Method method, TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {
        return false;
    }

    @Override
    public boolean sqlMapCountByExampleElementGenerated(XmlElement element, IntrospectedTable introspectedTable) {
        return false;
    }

    @Override
    public boolean sqlMapDeleteByExampleElementGenerated(XmlElement element, IntrospectedTable introspectedTable) {
        return false;
    }

    @Override
    public boolean sqlMapExampleWhereClauseElementGenerated(XmlElement element, IntrospectedTable introspectedTable) {
        return false;
    }

    @Override
    public boolean clientDeleteByExampleMethodGenerated(Method method, Interface interfaze, IntrospectedTable introspectedTable) {
        return false;
    }

    @Override
    public boolean clientDeleteByExampleMethodGenerated(Method method, TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {
        return false;
    }

    @Override
    public boolean clientSelectByExampleWithBLOBsMethodGenerated(Method method, Interface interfaze, IntrospectedTable introspectedTable) {
        return false;
    }

    @Override
    public boolean clientSelectByExampleWithBLOBsMethodGenerated(Method method, TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {
        return false;
    }

    @Override
    public boolean clientSelectByExampleWithoutBLOBsMethodGenerated(Method method, Interface interfaze, IntrospectedTable introspectedTable) {
        return false;
    }

    @Override
    public boolean clientSelectByExampleWithoutBLOBsMethodGenerated(Method method, TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {
        return false;
    }

    @Override
    public boolean clientUpdateByExampleSelectiveMethodGenerated(Method method, Interface interfaze, IntrospectedTable introspectedTable) {
        return false;
    }

    @Override
    public boolean clientUpdateByExampleSelectiveMethodGenerated(Method method, TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {
        return false;
    }

    @Override
    public boolean clientUpdateByExampleWithBLOBsMethodGenerated(Method method, Interface interfaze, IntrospectedTable introspectedTable) {
        return false;
    }

    @Override
    public boolean clientUpdateByExampleWithBLOBsMethodGenerated(Method method, TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {
        return false;
    }

    @Override
    public boolean clientUpdateByExampleWithoutBLOBsMethodGenerated(Method method, Interface interfaze, IntrospectedTable introspectedTable) {
        return false;
    }

    @Override
    public boolean clientUpdateByExampleWithoutBLOBsMethodGenerated(Method method, TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {
        return false;
    }

    @Override
    public boolean modelExampleClassGenerated(TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {
        return false;
    }

    @Override
    public boolean sqlMapSelectByExampleWithoutBLOBsElementGenerated(XmlElement element, IntrospectedTable introspectedTable) {
        return false;
    }

    @Override
    public boolean sqlMapSelectByExampleWithBLOBsElementGenerated(XmlElement element, IntrospectedTable introspectedTable) {
        return false;
    }

    @Override
    public boolean sqlMapUpdateByExampleSelectiveElementGenerated(XmlElement element, IntrospectedTable introspectedTable) {
        return false;
    }

    @Override
    public boolean sqlMapUpdateByExampleWithBLOBsElementGenerated(XmlElement element, IntrospectedTable introspectedTable) {
        return false;
    }

    @Override
    public boolean sqlMapUpdateByExampleWithoutBLOBsElementGenerated(XmlElement element, IntrospectedTable introspectedTable) {
        return false;
    }

    @Override
    public boolean providerCountByExampleMethodGenerated(Method method, TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {
        return false;
    }

    @Override
    public boolean providerDeleteByExampleMethodGenerated(Method method, TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {
        return false;
    }

    @Override
    public boolean providerInsertSelectiveMethodGenerated(Method method, TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {
        return false;
    }

    @Override
    public boolean providerSelectByExampleWithBLOBsMethodGenerated(Method method, TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {
        return false;
    }

    @Override
    public boolean providerSelectByExampleWithoutBLOBsMethodGenerated(Method method, TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {
        return false;
    }

    @Override
    public boolean providerUpdateByExampleSelectiveMethodGenerated(Method method, TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {
        return false;
    }

    @Override
    public boolean providerUpdateByExampleWithBLOBsMethodGenerated(Method method, TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {
        return false;
    }

    @Override
    public boolean providerUpdateByExampleWithoutBLOBsMethodGenerated(Method method, TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {
        return false;
    }

}
